package com.idea.relax.mybatis.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.idea.relax.mybatis.interceptor.QueryInterceptor;
import com.idea.relax.mybatis.page.PaginationInterceptor;
import com.idea.relax.mybatis.sql.SqlLogInterceptor;
import com.idea.relax.mybatis.tenant.ITenantIdHandler;
import com.idea.relax.mybatis.tenant.RelaxTenantLineHandler;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @className: RelaxCacheAutoConfiguration
 * @description:
 * @author: salad
 * @date: 2022/10/9
 **/
@AllArgsConstructor
@Configuration
@EnableConfigurationProperties(RelaxMybatisProperties.class)
@PropertySource(value = "classpath:mybatis.yml", factory = YamlPropertySourceFactory.class)
public class MybatisPlusConfiguration {

	private final RelaxMybatisProperties properties;


	@Bean
	@ConditionalOnMissingBean(TenantLineHandler.class)
	@ConditionalOnProperty(value = RelaxMybatisProperties.PREFIX + ".tenant.enabled", havingValue = "true")
	public TenantLineHandler tenantLineHandler(ObjectProvider<ITenantIdHandler> objectProvider) {
		ITenantIdHandler tenantIdHandler = objectProvider.getIfAvailable();
		Assert.isTrue(tenantIdHandler != null, "请实现ITenantIdHandler接口来设置租户ID");
		return new RelaxTenantLineHandler(properties.getTenant(), tenantIdHandler);
	}

	@Bean
	@ConditionalOnMissingBean(TenantLineInnerInterceptor.class)
	@ConditionalOnProperty(value = RelaxMybatisProperties.PREFIX + ".tenant.enabled", havingValue = "true")
	public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantLineHandler tenantLineHandler) {
		TenantLineInnerInterceptor interceptor = new TenantLineInnerInterceptor();
		interceptor.setTenantLineHandler(tenantLineHandler);
		return interceptor;
	}

	/**
	 * 分页插件
	 */
	@Bean
	@ConditionalOnProperty(value = RelaxMybatisProperties.PREFIX + ".enabled", havingValue = "true", matchIfMissing = true)
	public MybatisPlusInterceptor mybatisPlusInterceptor(ObjectProvider<QueryInterceptor> queryInterceptors, ObjectProvider<TenantLineInnerInterceptor> provider) {
		List<QueryInterceptor> queryInterceptorList = queryInterceptors.stream()
			.sorted(Comparator.comparing(QueryInterceptor::getOrder)).collect(Collectors.toList());
		MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
		PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
		if (!ObjectUtils.isEmpty(queryInterceptorList)) {
			paginationInterceptor.setQueryInterceptors(queryInterceptorList);
		}
		paginationInterceptor.setOverflow(properties.getPagination().isOverflow());
		paginationInterceptor.setMaxLimit(properties.getPagination().getPageLimit());
		interceptor.addInnerInterceptor(paginationInterceptor);
		provider.ifAvailable(interceptor::addInnerInterceptor);
		OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
		interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
		return interceptor;
	}

	/**
	 * sql 日志
	 */
	@Bean
	@ConditionalOnProperty(value = RelaxMybatisProperties.PREFIX + ".sql-log.enabled", havingValue = "true", matchIfMissing = true)
	public SqlLogInterceptor sqlLogInterceptor() {
		return new SqlLogInterceptor(properties);
	}

}
